package org.common.utils.net.netty.http.core;

import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.QueryStringDecoder;
import org.common.utils.net.netty.http.exception.HttpNotFoundParamException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * http请求实体
 * @author zhouzhibing
 * @date 2025/11/20 17:06
 */
public class HttpRequest {

    private static final Logger log = LoggerFactory.getLogger(HttpRequest.class);

    /**
     * HTTP请求
     */
    private final FullHttpRequest request;
    /**
     * 路由信息
     */
    private final RouteInfo routeInfo;
    /**
     * 请求方法
     */
    private HttpMethod method;
    /**
     * 请求参数
     */
    private Map<String, String> queryParams;
    /**
     * 路径参数
     */
    private Map<String, String> pathParams;
    /**
     * 请求头参数
     */
    private Map<String, String> headers;
    /**
     * 请求体
     */
    private String body;
    /**
     * 请求路径
     */
    private String requestPath;

    public HttpRequest(FullHttpRequest request, RouteInfo routeInfo) {
        this.request = request;
        this.requestPath = request.uri();
        this.method = request.method();
        this.routeInfo = routeInfo;
    }

    /**
     * 获取查询参数
     * @return 查询参数
     */
    public Map<String, String> getQueryParams() {
        if(queryParams == null) {
            // 解析查询参数
            QueryStringDecoder queryDecoder = new QueryStringDecoder(request.uri());
            Map<String, List<String>> parameters = queryDecoder.parameters();
            queryParams = new HashMap<>(parameters.size());
            queryDecoder.parameters().forEach((key, value) -> {
                queryParams.put(key, value.get(0));
            });
        }
        return queryParams;
    }

    /**
     * 获取路径参数
     * @return 路径参数
     */
    public Map<String, String> getPathParams() {
        if(pathParams == null) {
            List<String> pathParamNames = routeInfo.getPathParamNames();
            // 如果没有路径参数，则返回空
            if(pathParamNames == null || pathParamNames.isEmpty()) {
                pathParams = Collections.emptyMap();
            } else {
                // 解析路径参数
                this.pathParams = new HashMap<>(pathParamNames.size());
                String[] pathSplits = request.uri().split(routeInfo.getPath());
                if(pathSplits.length == 0) {
                    log.warn("Request path, path parameter is undefined. （请求路径，未定义路径参数）, requestPath = {}" , requestPath);
                    pathParams = Collections.emptyMap();
                    return pathParams;
                }

                String[] pathSegments = pathSplits[1].split("/");
                List<MethodParam> methodParams = routeInfo.getMethodParamNames();
                for (MethodParam methodParam : methodParams) {
                    String methodParamName = methodParam.getName();
                    int methodParamIndex = getMethodParamInPathIndex(methodParamName, pathParamNames);
                    pathParams.put(methodParamName, pathSegments[methodParamIndex + 1]);
                }
            }
        }
        return pathParams;
    }

    /**
     * 获取请求头参数
     * @return 请求头参数
     */
    public Map<String, String> getHeaders() {
        if(headers == null) {
            // 解析请求头
            HttpHeaders reqHeaders = request.headers();
            this.headers = new HashMap<>(reqHeaders.size());
            reqHeaders.forEach(entry -> {
                headers.put(entry.getKey(), entry.getValue());
            });
        }
        return headers;
    }

    public String getBody() {
        if(body == null) {
            // 解析请求体
            if (request.content() != null && request.content().readableBytes() > 0) {
                body = request.content().toString(StandardCharsets.UTF_8);
            }
        }
        return body;
    }

    /**
     * 获取方法参数在路径参数中的索引
     * @param methodParamName 方法参数名
     * @param pathParamNames 路径参数名
     * @return 方法参数在路径参数中的索引
     */
    private int getMethodParamInPathIndex(String methodParamName, List<String> pathParamNames) {
        int methodParamIndex = -1;
        for (int i = 0, length = pathParamNames.size(); i < length; i++) {
            if(methodParamName.equals(pathParamNames.get(i))){
                methodParamIndex = i;
                break;
            }
        }
        // 没有找到对应的方法参数
        if(methodParamIndex == -1) {
            throw new HttpNotFoundParamException(requestPath + " : " + methodParamName);
        }
        return methodParamIndex;
    }

    public HttpMethod getMethod() {
        return method;
    }

    @Override
    public String toString() {
        return "HttpRequest{" +
                "method=" + method +
                ", queryParams=" + queryParams +
                ", pathParams=" + pathParams +
                ", headers=" + headers +
                ", body='" + body + '\'' +
                ", requestPath='" + requestPath + '\'' +
                '}';
    }
}
